export function getDimensionConfig(array) {
  let result = [];
  if (array) {
    _.each(array, function(e) {
      if (_.isUndefined(e.group)) {
        result.push({
          columnName: e.col,
          filterType: e.type,
          values: e.values,
          id: e.id
        });
      } else {
        _.each(e.filters, function(f) {
          result.push({
            columnName: f.col,
            filterType: f.type,
            values: f.values
          });
        });
      }
    });
  }
  return result;
};

// 维度列筛选
export function getToByOne(columnList, rowList, dimensionList) {
  let arrylst = [];
  let collst = [];
  for (let i = 0; i < columnList.length; i++) {
    collst.push(columnList[i]);
  }
  for (let i = 0; i < rowList.length; i++) {
    collst.push(rowList[i]);
  }
  if(collst.length){
    for (let i = 0; i < dimensionList.length; i++) {
      for (let j = 0; j < collst.length; j++) {
        if (dimensionList[i].column == collst[j].col) {
          break;
        }
        if (j == collst.length - 1) {
          arrylst.push(dimensionList[i])
        }
      }
    }
  }else{
    arrylst = dimensionList
  }

  return arrylst;
}

// 表达式筛选
export function expAndFilterLink(targetList, expList) {
  let arrList = []
  let collList = []
  for (let i = 0; i < targetList.length; i++) {
    collList.push(targetList[i]);
  }
  if(collList.length){
    for (let i = 0; i < expList.length; i++) {
      for (let j = 0; j < collList.length; j++) {
        if (expList[i].timestamp == collList[j].timestamp) {
          break;
        }
        if (j == collList.length - 1) {
          arrList.push(expList[i])
        }
      }
    }
  }else{
    arrList = expList
  }

  return arrList;
}

export function getDataSeries(chartConfig) {
  let that = this
  let result = [];
  _.each(chartConfig.values, function(v) {
    _.each(v.cols, function(c) {
      let series = configToDataSeries(c);
      _.each(series, function(s) {
        if (!_.find(result, function(e) {
            return JSON.stringify(e) == JSON.stringify(s);
          })) {
          result.push(s);
        }
      });
    });
  });
  return result;
};

export function configToDataSeries(config) {
  switch (config.type) {
    case 'exp':
      return getExpSeries(config.exp);
      break;
    default:
      return [{
        name: config.col,
        aggregate: config.aggregate_type
      }];
      break;
  }
};

export function getExpSeries(exp) {
  return parserExp(exp).aggs;
}

export function parserExp(rawExp) {
  let evalExp = rawExp;
  let _temp = [];
  let aggs = [];
  evalExp = evalExp.trim().replace(/[\n|\r|\r\n]/g, '');

  _.each(evalExp.match(/".*?"/g), function(qutaText) {
    evalExp = evalExp.replace(qutaText, '_#' + _temp.length);
    _temp.push(qutaText);
  });

  let names = []; // expression text in aggreagtion function, could be a columnName or script
  _.each(evalExp.match(/(sum|avg|count|max|min|distinct)\("?.*?"?\)/g), function(aggUnit) {
    let aggregate = aggUnit.substring(0, aggUnit.indexOf('('));
    let name = aggUnit.substring(aggUnit.indexOf('(') + 1, aggUnit.indexOf(')'));
    if (name.match("_#")) {
      name = _temp[name.replace("_#", "")].replace(/\"/g, "");
    }
    evalExp = evalExp.replace(aggUnit, "groupData[_names[" + names.length + "]]['" + aggregate + "'][key]");
    names.push(name);
    aggs.push({
      name: name,
      aggregate: aggregate
    });
  });
  return {
    evalExp: evalExp,
    aggs: aggs,
    names: names
  };
}

export function castRawData2Series(aggData, chartConfig) {
  var castedKeys = new Array();
  var castedGroups = new Array();
  var joinedKeys = {};
  var joinedGroups = {};
  var newData = {};
  var getIndex = function(columnList, col) {
    var result = new Array();
    if (col) {
      for (var j = 0; j < col.length; j++) {
        var idx = _.find(columnList, function(e) {
          return e.name == col[j];
        });
        result.push(idx.index);
      }
    }
    return result;
  };
  var filter = function(cfg, iv) {
    switch (cfg.f_type) {
      case '=':
      case 'eq':
        for (var i = 0; i < cfg.f_values.length; i++) {
          if (iv == cfg.f_values[i]) {
            return true;
          }
        }
        return cfg.f_values.length == 0;
      case '≠':
      case 'ne':
        for (var i = 0; i < cfg.f_values.length; i++) {
          if (iv == cfg.f_values[i]) {
            return false;
          }
        }
        return true;
      case '>':
        var v = cfg.f_values[0];
        var params = toNumber(iv, v);
        if (!_.isUndefined(v) && params[0] <= params[1]) {
          return false;
        }
        return true;
      case '<':
        var v = cfg.f_values[0];
        var params = toNumber(iv, v);
        if (!_.isUndefined(v) && params[0] >= params[1]) {
          return false;
        }
        return true;
      case '≥':
        var v = cfg.f_values[0];
        var params = toNumber(iv, v);
        if (!_.isUndefined(v) && params[0] < params[1]) {
          return false;
        }
        return true;
      case '≤':
        var v = cfg.f_values[0];
        var params = toNumber(iv, v);
        if (!_.isUndefined(v) && params[0] > params[1]) {
          return false;
        }
        return true;
      case '(a,b]':
        var a = cfg.f_values[0];
        var b = cfg.f_values[1];
        var params = toNumber(iv, a, b);
        if (!_.isUndefined(a) && !_.isUndefined(b) && (params[0] <= params[1] || params[0] > params[2])) {
          return false;
        }
        return true;
      case '[a,b)':
        var a = cfg.f_values[0];
        var b = cfg.f_values[1];
        var params = toNumber(iv, a, b);
        if (!_.isUndefined(a) && !_.isUndefined(b) && (params[0] < params[1] || params[0] >= params[2])) {
          return false;
        }
        return true;
      case '(a,b)':
        var a = cfg.f_values[0];
        var b = cfg.f_values[1];
        var params = toNumber(iv, a, b);
        if (!_.isUndefined(a) && !_.isUndefined(b) && (params[0] <= params[1] || params[0] >= params[2])) {
          return false;
        }
        return true;
      case '[a,b]':
        var a = cfg.f_values[0];
        var b = cfg.f_values[1];
        var params = toNumber(iv, a, b);
        if (!_.isUndefined(a) && !_.isUndefined(b) && (params[0] < params[1] || params[0] > params[2])) {
          return false;
        }
        return true;
      default:
        return true;
    }
  };

  var toNumber = function() {
    var arr = _.isArray(arguments[0]) ? arguments[0] : arguments;
    var result = [];
    for (var i = 0; i < arr.length; i++) {
      var a = Number(arr[i]);
      if (isNaN(a)) {
        return arr;
      } else {
        result.push(a);
      }
    }
    return result;
  };

  var getRowElements = function(row, elmIdxs) {
    var arr = new Array();
    for (var j = 0; j < elmIdxs.length; j++) {
      var elm = row[elmIdxs[j]];
      arr.push(elm);
    }
    return arr;
  };

  var castSeriesData = function(series, group, castedKeys, newData, iterator) {
    switch (series.type) {
      case 'exp':
        var runExp = compileExp(series.exp);
        for (var i = 0; i < castedKeys.length; i++) {
          iterator(runExp(newData[group], castedKeys[i].join('-')), i);
        }
        break;
      default:
        for (var i = 0; i < castedKeys.length; i++) {
          iterator(newData[group][series.col][series.aggregate_type][castedKeys[i].join('-')], i)
        }
        break;
    }
  };

  var compileExp = function (exp) {
      var parseredExp = parserExp(exp);
      return function (groupData, key) {
          var _names = parseredExp.names;
          return eval(parseredExp.evalExp);
      };
  };

  var keysIdx = getIndex(aggData.columnList, _.map(chartConfig.keys, function(e) {
    return e.col;
  }));
  var keysSort = _.map(chartConfig.keys, function(e) {
    return e.sort;
  });
  var groupsIdx = getIndex(aggData.columnList, _.map(chartConfig.groups, function(e) {
    return e.col;
  }));
  var groupsSort = _.map(chartConfig.groups, function(e) {
    return e.sort;
  });

  var valueSeries = _.filter(aggData.columnList, function(e) {
    return e.aggType;
  });
  for (var i = 0; i < aggData.data.length; i++) {
    //组合keys
    var newKey = getRowElements(aggData.data[i], keysIdx);
    var jk = newKey.join('-');
    if (_.isUndefined(joinedKeys[jk])) {
      castedKeys.push(newKey);
      joinedKeys[jk] = true;
    }
    //组合groups
    var group = getRowElements(aggData.data[i], groupsIdx);
    var newGroup = group.join('-');
    if (_.isUndefined(joinedGroups[newGroup])) {
      castedGroups.push(group);
      joinedGroups[newGroup] = true;
    }
    // pick the raw values into coordinate cell and then use aggregate function to do calculate
    _.each(valueSeries, function(dSeries) {
      if (_.isUndefined(newData[newGroup])) {
        newData[newGroup] = {};
      }
      if (_.isUndefined(newData[newGroup][dSeries.name])) {
        newData[newGroup][dSeries.name] = {};
      }
      if (_.isUndefined(newData[newGroup][dSeries.name][dSeries.aggType])) {
        newData[newGroup][dSeries.name][dSeries.aggType] = {};
      }
      newData[newGroup][dSeries.name][dSeries.aggType][jk] = parseFloat(aggData.data[i][dSeries.index]);
    });
  }
  let that = this
  // //sort dimension
  var getSort = function(sort) {
    return function(a, b) {
      var r = 0;
      var j = 0;
      for (; j < a.length; j++) {
        if (!sort[j]) {
          continue;
        }
        if (a[j] == b[j]) {
          r = 0;
          continue;
        }
        var params = toNumber(a[j], b[j]);
        r = (params[0] > params[1]) ? 1 : -1;
        if (sort[j] == 'desc') r = r * -1;
        break;
      }
      return r;
    }
  };
  castedKeys.sort(getSort(keysSort));
  castedGroups.sort(getSort(groupsSort));
  // //
  var castedAliasSeriesName = new Array();
  var aliasSeriesConfig = {};
  var aliasData = new Array();

  var valueSort = undefined;
  var valueSortArr = [];

  _.each(castedGroups, function(group) {
    _.each(chartConfig.values, function(value) {
      _.each(value.cols, function(series) {
        if (_.isUndefined(valueSort) && series.sort) {
          valueSort = series.sort;
          castSeriesData(series, group.join('-'), castedKeys, newData, function(castedData, keyIdx) {
            valueSortArr[keyIdx] = {
              v: castedData,
              i: keyIdx
            };
          });
        }
      });
    });
  });

  if (!_.isUndefined(valueSort)) {
    valueSortArr.sort(function(a, b) {
      if (a.v == b.v) return 0;
      var p = toNumber(a.v, b.v)
      if ((p[0] < p[1]) ^ valueSort == 'asc') {
        return 1;
      } else {
        return -1;
      }
    });
    var tk = angular.copy(castedKeys);
    _.each(valueSortArr, function(e, i) {
      castedKeys[i] = tk[e.i];
    });
  }

  _.each(castedGroups, function(group) {
    _.each(chartConfig.values, function(value, vIdx) {
      _.each(value.cols, function(series) {
        var seriesName = series.alias ? series.alias : series.col;
        var newSeriesName = seriesName;
        if (group && group.length > 0) {
          var a = [].concat(group);
          a.push(seriesName);
          newSeriesName = a.join('-');
          castedAliasSeriesName.push(a);
        } else {
          castedAliasSeriesName.push([seriesName]);
        }
        //castedAliasSeriesName.push(newSeriesName);
        aliasSeriesConfig[newSeriesName] = {
          type: value.series_type,
          valueAxisIndex: vIdx,
          formatter: series.formatter
        };
        castSeriesData(series, group.join('-'), castedKeys, newData, function(castedData, keyIdx) {
          if (!aliasData[castedAliasSeriesName.length - 1]) {
            aliasData[castedAliasSeriesName.length - 1] = new Array();
          }
          // Only format decimal
          aliasData[castedAliasSeriesName.length - 1][keyIdx] = castedData;
        });
      });
    });
  });
  for (var i = 0; i < castedKeys.length; i++) {
    var s = 0;
    var f = true;
    _.each(castedGroups, function(group) {
      _.each(chartConfig.values, function(value) {
        _.each(value.cols, function(series) {
          if (!f) {
            return;
          }
          if (series.f_top && series.f_top <= i) {
            f = false;
          }
          if (!filter(series, aliasData[s][i])) {
            f = false;
          }
          // if (f) {
          //   aliasData[s][i] = aliasData[s][i];
          // }
          s++;
        });
      });
    });
    if (!f) {
      castedKeys.splice(i, 1);
      _.each(aliasData, function(_series) {
        _series.splice(i, 1);
      });
      i--;
    }
  }
  return {
    keys: castedKeys,
    series: castedAliasSeriesName,
    data: aliasData,
    seriesConfig: aliasSeriesConfig
  };

}
